/*
 * User: rant
 * Date: 07/02/2007
 *
 *
 */
package laMalinche.rete.nodes.editing;

import laMalinche.editableContext.AboutToChangeManager;
import laMalinche.editableContext.CertaintyChangeEvent;
import laMalinche.rete.nodes.BasicConditionNode;
import laMalinche.rete.nodes.ConditionNode;
import laMalinche.rete.nodes.StopEvaluatingException;
import laMalinche.rete.nodes.tailing.ActObservableHolder;
import laMalinche.rete.nodes.tailing.WorkingMemory;
import laMalinche.rete.nodes.tailing.WorkingMemoryListenable;
import laMalinche.rete.rule.ConditionObservable;
import laMalinche.testingPlayGround.testModel.EntityChangeEvent;
import laMalinche.testingPlayGround.testModel.VOEntity;
import org.apache.commons.lang.StringUtils;

import java.util.*;

/**
 *
 */
public class OpenFieldCertaintyManager extends WorkingMemoryListenable implements CertaintyManager {
    private List<VOEntity> relevantFields;
    private AboutToChangeManager aboutToChangeManager;
    private String openTouchedElement;
    private ConditionNode<ConditionObservable> basicTailingsConditionNode;

    public WorkingMemory getWorkingMemory() {
        return ((BasicConditionNode<ConditionObservable>) getConditionNode()).getWorkingMemory();
    }

    public void setOpenTouchedElement(final String openTouchedElement) {
        if (!StringUtils.equalsIgnoreCase(openTouchedElement, this.openTouchedElement)) {
            this.openTouchedElement = openTouchedElement;
            adviseListeners(isCertain());
        }
    }

    public ConditionNode<ConditionObservable> getConditionNode() {
        return basicTailingsConditionNode;
    }

    public void setConditionNode(final ConditionNode<ConditionObservable> basicTailingsConditionNode) {
        this.basicTailingsConditionNode = basicTailingsConditionNode;
    }

    public void certaintyChange(CertaintyChangeEvent e) {
        if (getWorkingMemory() == null) {
            return;
        }
        String openTouchedField = getOpenTouchedElement();
        Set<String> unCertain = aboutToChangeManager.getAboutToChangeElements();
        relevantFields = getWorkingMemory().getRelevantFields();
        if (unCertain != null && !unCertain.isEmpty()) {
            if (isUnCertain(relevantFields, unCertain)) {
                return;
            }
        }
        if (openTouchedField != null && (unCertain == null || unCertain.isEmpty())
                || !containsIgnoreCase(unCertain, openTouchedField)) {
            setOpenTouchedElement(null);
        }
    }

    private boolean isUnCertain(final List<VOEntity> lRelevantElements, final Set<String> becameUnCertain) {
        for (VOEntity relevantElement : lRelevantElements) {
            final List<VOEntity> newRelevantElements = new ArrayList<VOEntity>(10);
            newRelevantElements.add(relevantElement);
            String releveant = relevantElement.getOgnl();
            if (becameUnCertain != null && containsIgnoreCase(becameUnCertain, releveant)) {
                setOpenTouchedElement(releveant);
                relevantFields = newRelevantElements;
                // TODO make not valid
                getWorkingMemory().adviseCahnge();
                return true;
            }
        }
        return false;
    }

    private boolean containsIgnoreCase(final Set<String> set, final String releveant) {
        for (String s : set) {
            if (StringUtils.equalsIgnoreCase(s, releveant)) {
                return true;
            }
        }
        return false;
    }

    public void propertyChange(EntityChangeEvent event) {

    }

    private void stopRuleExecution() {
        if (getConditionNode() != null) {
            ((ActObservableHolder) getConditionNode()).stopRuleExecution();
        } else {
            throw new StopEvaluatingException();
        }
    }

    public AboutToChangeManager getAboutToChangeManager() {
        return aboutToChangeManager;
    }

    public void setAboutToChangeManager(AboutToChangeManager aboutToChangeManager) {
        this.aboutToChangeManager = aboutToChangeManager;
    }

    public boolean isCertain() {
        return getOpenTouchedElement() == null;
    }

    public String getOpenTouchedElement() {
        return openTouchedElement;
    }

    public void detach() {
    }

    public void propertyTouched(VOEntity entity) {
        // todo ran make Ognl object support generalizations
        String generalizedOgnl = entity.getGeneralizeOgnl();
        Set<String> aboutToChangeElements = getAboutToChangeManager().getAboutToChangeElements();
        if (aboutToChangeElements != null) {
            for (String exluded : aboutToChangeElements) {
                if (exluded.equalsIgnoreCase(generalizedOgnl)) {
                    setOpenTouchedElement(generalizedOgnl);
                    stopRuleExecution();
                    break;
                }
            }
        }
    }
     //


    public void actCompleted(List<VOEntity> elements) {
    }
}